﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace NeedForSmash
{
    class Character : DrawableGameComponent
    {
        protected Quad m_quad;
        protected Texture2D m_texture;
        private BasicEffect m_quadEffect;
        private VertexDeclaration m_vertexDeclaration;

        protected Animation m_animationWalk;

        private BoundingBox m_boundingBox;
        public BoundingBox BoundingBox
        {
            get
            {
                return m_boundingBox;
            }
            set
            {
                m_boundingBox = value;
            }
        }

        private BoundingBox m_oldBoundingBox;

        private Vector3 m_position;
        public Vector3 Position
        {
            get
            {
                return m_position;
            }
            set
            {
                m_position = value;
            }
        }

        private Vector3 m_oldPosition;

        private Vector3 m_velocity;
        public Vector3 Velocity
        {
            get
            {
                return m_velocity;
            }
            set
            {
                m_velocity = value;
            }
        }

        private Game m_game;
        public Game GameCore
        {
            get
            {
                return this.m_game;
            }
            private set
            {
                m_game = value;
            }
        }

        public Character(Game game)
            : base(game)
        {
            GameCore = game;
            m_quadEffect = new BasicEffect(GameCore.GraphicsDevice);
            m_vertexDeclaration = new VertexDeclaration(new VertexElement[]
                {
                    new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0),
                    new VertexElement(12, VertexElementFormat.Vector3, VertexElementUsage.Normal, 0),
                    new VertexElement(24, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0)
                }
            );
        }

        public override void Initialize()
        {
            m_quadEffect.EnableDefaultLighting();
            m_quadEffect.World = Matrix.Identity;
            m_quadEffect.TextureEnabled = true;
            m_quadEffect.Texture = m_texture;

            m_texture.GraphicsDevice.BlendState = BlendState.AlphaBlend;

            m_boundingBox = CalculateBoundingBox();

            base.Initialize();
        }

        protected override void LoadContent()
        {
            base.LoadContent();
        }

        public override void Draw(GameTime gameTime)
        {
            m_quadEffect.View = GameCore.Camera.ViewMatrix;
            m_quadEffect.Projection = GameCore.Camera.ProjectionMatrix;

            foreach (EffectPass pass in m_quadEffect.CurrentTechnique.Passes)
            {
                pass.Apply();

                GameCore.GraphicsDevice.DrawUserIndexedPrimitives
                    <VertexPositionNormalTexture>(
                    PrimitiveType.TriangleList,
                    m_quad.Vertices, 0, 4,
                    m_quad.Indexes, 0, 2);
            }
#if DEBUG
            DrawBox(m_boundingBox);
#endif
            base.Draw(gameTime);
        }

        public override void Update(GameTime gameTime)
        {
            UpdateGamepad(gameTime);
            UpdateKeyboard(gameTime);
            base.Update(gameTime);
        }

        private void UpdateGamepad(GameTime gameTime)
        {
            GamePadState currentState = GamePad.GetState(PlayerIndex.One);

            // Process input only if connected and button A is pressed.
            if (currentState.Buttons.A == ButtonState.Pressed)
            {
                // Button A is currently being pressed; add vibration.
                Console.WriteLine("Button A pressed !");
            }
            if (currentState.Buttons.Y == ButtonState.Pressed)
            {
                // Button A is currently being pressed; add vibration.
                Console.WriteLine("Button Y pressed !");
                Jump();
            }

            Move(new Vector3(currentState.ThumbSticks.Left.X * (float)gameTime.ElapsedGameTime.Milliseconds / 400.0f, 0, 0));
        }

        private void UpdateKeyboard(GameTime gameTime)
        {
            KeyboardState currentState = Keyboard.GetState();

#if DEBUG
            if (currentState.IsKeyDown(Keys.Left))
            {
                Move(new Vector3(-10000 * (float)gameTime.ElapsedGameTime.Milliseconds / 400.0f, 0, 0));
            }
            else if (currentState.IsKeyDown(Keys.Right))
            {
                Move(new Vector3(10000 * (float)gameTime.ElapsedGameTime.Milliseconds / 400.0f, 0, 0));
            }
#endif
        }

        private BoundingBox CalculateBoundingBox()
        {
            return new BoundingBox(new Vector3(m_quad.LowerLeft.X, m_quad.LowerLeft.Y, m_quad.LowerLeft.Z - 0.1f),
                new Vector3(m_quad.UpperRight.X, m_quad.UpperRight.Y, m_quad.UpperRight.Z + 0.1f));
        }

        public void Jump()
        {
            m_velocity.Y = 2.0f;
        }

        public void Move(Vector3 v)
        {
            m_oldPosition = m_quad.Origin;
            m_oldBoundingBox = m_boundingBox;
            m_quad.Origin += v;
            m_quad.Refresh();
            m_boundingBox.Min += v;
            m_boundingBox.Max += v;
        }

        public void Backup()
        {
            m_quad.Origin = m_oldPosition;
            m_quad.Refresh();
            m_boundingBox = m_oldBoundingBox;
        }

        public void StopMove()
        {
            m_velocity = new Vector3(0, 0, 0);
        }

        VertexPositionColor[] points;
        short[] index;
        BasicEffect lineShader;

        protected void DrawBox(BoundingBox box)
        {
            BuildBox(box, Color.White);
            DrawLines(12);
        }

        protected void BuildBox(BoundingBox box, Color lineColor)
        {
            points = new VertexPositionColor[8];

            Vector3[] corners = box.GetCorners();

            points[0] = new VertexPositionColor(corners[1], lineColor); // Front Top Right
            points[1] = new VertexPositionColor(corners[0], lineColor); // Front Top Left
            points[2] = new VertexPositionColor(corners[2], lineColor); // Front Bottom Right
            points[3] = new VertexPositionColor(corners[3], lineColor); // Front Bottom Left
            points[4] = new VertexPositionColor(corners[5], lineColor); // Back Top Right
            points[5] = new VertexPositionColor(corners[4], lineColor); // Back Top Left
            points[6] = new VertexPositionColor(corners[6], lineColor); // Back Bottom Right
            points[7] = new VertexPositionColor(corners[7], lineColor); // Bakc Bottom Left

            index = new short[] {
	            0, 1, 0, 2, 1, 3, 2, 3,
	            4, 5, 4, 6, 5, 7, 6, 7,
	            0, 4, 1, 5, 2, 6, 3, 7
                };
        }

        protected void DrawLines(int primativeCount)
        {
            if (lineShader == null)
                lineShader = new BasicEffect(GraphicsDevice);

            lineShader.World = Matrix.Identity;
            lineShader.View = m_game.Camera.ViewMatrix;
            lineShader.Projection = m_game.Camera.ProjectionMatrix;
            lineShader.VertexColorEnabled = true;

            lineShader.CurrentTechnique.Passes[0].Apply();
            GraphicsDevice.DrawUserIndexedPrimitives<VertexPositionColor>(PrimitiveType.LineList, points, 0, points.Length, index, 0, primativeCount);
        }
    }
}
